﻿// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;

namespace Azure.AI.Inference
{
    /// <summary>
    /// Represents an optional control that specifies which, if any, tools may be called by the model while processing a
    /// chat completions request.
    /// </summary>
    /// <remarks>
    /// <list type="bullet">
    /// <item>
    ///     <see cref="None"/> is the default when no tools are provided and specifies that the model should not use any
    ///     tools and instead always generate a message. Note that available tools may still influence the content of
    ///     messages as generated by the model even when they are not or cannot be selected.
    /// </item>
    /// <item>
    ///     <see cref="Auto"/> is the default when tools are provided and specifies that the model should freely
    ///     determine if, and which, tools should be called instead of generating a message.
    /// </item>
    /// <item>
    ///     Providing a <see cref="FunctionDefinition"/> or <see cref="ChatCompletionsToolDefinition"/> will
    ///     request that the model constrains its response to only calling the specified function tool.
    /// </item>
    /// </list>
    /// Note: with 1106 model revisions, constraining the model to a specific function via tool_choice will provide a
    /// finish_reason of 'stop'. Please check for 'tool_calls' rather than relying on a consistent finish_reason.
    /// </remarks>
    public partial class ChatCompletionsToolChoice
    {
        /// <inheritdoc cref="ChatCompletionsToolChoicePreset.Auto"/>
        public static readonly ChatCompletionsToolChoice Auto = new(ChatCompletionsToolChoicePreset.Auto);

        /// <inheritdoc cref="ChatCompletionsToolChoicePreset.None"/>
        public static readonly ChatCompletionsToolChoice None = new(ChatCompletionsToolChoicePreset.None);

        /// <inheritdoc cref="ChatCompletionsToolChoicePreset.Required"/>
        public static readonly ChatCompletionsToolChoice Required = new(ChatCompletionsToolChoicePreset.Required);

        public static implicit operator ChatCompletionsToolChoice(FunctionDefinition functionDefinition)
        {
            return new(functionDefinition);
        }

        public static implicit operator ChatCompletionsToolChoice(ChatCompletionsToolDefinition functionToolDefinition)
        {
            return new(functionToolDefinition);
        }

        /// <summary>
        /// Initializes a new instance of <see cref="ChatCompletionsToolChoice"/> that requests the model constrains its
        /// response to calling a provided function tool that matches the name of the provided
        /// <see cref="FunctionDefinition"/>.
        /// </summary>
        /// <param name="functionDefinition">
        ///     A <see cref="FunctionDefinition"/> with a name that matches the function tool to which model responses
        ///     should be constrained.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="functionDefinition"/> is null.
        /// </exception>
        public ChatCompletionsToolChoice(FunctionDefinition functionDefinition)
        {
            Argument.AssertNotNull(functionDefinition, nameof(functionDefinition));
            Function = functionDefinition;
        }

        /// <summary>
        /// Initializes a new instance of <see cref="ChatCompletionsToolChoice"/> that requests the model constrains its
        /// response to calling a provided function tool definition that matches the name of the provided
        /// <see cref="FunctionDefinition"/>.
        /// </summary>
        /// <param name="functionToolDefinition">
        ///     A <see cref="ChatCompletionsToolDefinition"/> with a name that matches the function tool to which
        ///     model responses should be constrained.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="functionToolDefinition"/> is null.
        /// </exception>
        public ChatCompletionsToolChoice(ChatCompletionsToolDefinition functionToolDefinition)
        {
            Argument.AssertNotNull(functionToolDefinition, nameof(functionToolDefinition));
            Function = functionToolDefinition.Function;
        }

        internal ChatCompletionsToolChoice(ChatCompletionsToolChoicePreset preset)
        {
            Preset = preset;
        }

        internal FunctionDefinition Function { get; }

        internal ChatCompletionsToolChoicePreset Preset { get; }
    }
}
